package cn.signalpha.modules.shop.service;

import cn.hutool.core.date.DateUtil;
import cn.signalpha.common.cache.ConfigCache;
import cn.signalpha.common.cache.ConfigKeys;
import cn.signalpha.common.constant.MsgConstant;
import cn.signalpha.common.dto.ConfigDTO;
import cn.signalpha.common.utils.Arith;
import cn.signalpha.common.utils.Assert;
import cn.signalpha.common.utils.SnowflakeUtil;
import cn.signalpha.core.log.exception.ServiceException;
import cn.signalpha.core.log.logger.LoggerUtils;
import cn.signalpha.core.tool.jackson.JsonUtil;
import cn.signalpha.core.tool.support.Kv;
import cn.signalpha.core.tool.utils.*;
import cn.signalpha.modules.base.dto.NoticeDTO;
import cn.signalpha.modules.base.entity.enums.NoticeTypeEnum;
import cn.signalpha.modules.com.dto.WalletDTO;
import cn.signalpha.modules.com.entity.enums.WalletSourceEnum;
import cn.signalpha.modules.com.entity.enums.WalletTypeEnum;
import cn.signalpha.modules.com.service.UserService;
import cn.signalpha.modules.pay.dto.RefundDTO;
import cn.signalpha.modules.pay.provider.IPayGranter;
import cn.signalpha.modules.pay.provider.PayGranterBuilder;
import cn.signalpha.modules.pay.vo.RefundVO;
import cn.signalpha.modules.queue.enums.RedisDelayQueueEnum;
import cn.signalpha.modules.queue.utils.RedisDelayQueueUtil;
import cn.signalpha.modules.shop.dto.OrderRefundDTO;
import cn.signalpha.modules.shop.entity.*;
import cn.signalpha.modules.shop.entity.enums.CouponUseTypeEnum;
import cn.signalpha.modules.shop.entity.enums.OrderStatusEnum;
import cn.signalpha.modules.shop.excel.OrderRefundExcel;
import cn.signalpha.modules.shop.mapper.OrderRefundMapper;
import cn.signalpha.modules.shop.vo.OrderGoodsVO;
import cn.signalpha.modules.shop.vo.OrderRefundVO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 服务类
 *
 * @author signalpha
 */
@Service
@AllArgsConstructor
public class OrderRefundService extends ServiceImpl<OrderRefundMapper, OrderRefund> {

	private final LoggerUtils loggerUtils;
	private final UserService userService;
	private final OrderService orderService;
	private final SnowflakeUtil snowflakeUtil;
	private final SellerService sellerService;
	private final CouponUserService couponUserService;
	private final OrderCouponService orderCouponService;
	private final OrderDetailService orderDetailService;
	private final OrderSettleService orderSettleService;
	private final RedisDelayQueueUtil redisDelayQueueUtil;
	private final SellerAddressService sellerAddressService;
	private final OrderRefundLogService orderRefundLogService;
	private final OrderSettlePlaceService orderSettlePlaceService;

	/**
	 * 自定义分页
	 */
    public IPage<OrderRefundVO> selectOrderRefundPage(IPage<OrderRefundVO> page, Map<String, Object> params) {
        return page.setRecords(baseMapper.selectOrderRefundPage(page, params));
    }

	/**
	 * 自定义Wrapper
	 */
	public QueryWrapper<OrderRefund> selectOrderRefundWrapper(Map<String, Object> params) {
		QueryWrapper<OrderRefund> wrapper = Wrappers.query();
		wrapper.lambda().eq(ObjectUtil.isNotEmpty(params.get("sellerId")), OrderRefund::getSellerId, params.get("sellerId"));
		wrapper.lambda().eq(ObjectUtil.isNotEmpty(params.get("userId")), OrderRefund::getUserId, params.get("userId"));
		wrapper.lambda().eq(ObjectUtil.isNotEmpty(params.get("orderNo")), OrderRefund::getOrderNo, params.get("orderNo"));
		wrapper.lambda().eq(ObjectUtil.isNotEmpty(params.get("orderType")), OrderRefund::getOrderType, params.get("orderType"));
		wrapper.lambda().eq(ObjectUtil.isNotEmpty(params.get("refundNo")), OrderRefund::getRefundNo, params.get("refundNo"));
		wrapper.lambda().eq(ObjectUtil.isNotEmpty(params.get("refundType")), OrderRefund::getRefundType, params.get("refundType"));
		wrapper.lambda().eq(ObjectUtil.isNotEmpty(params.get("refundBizNo")), OrderRefund::getRefundBizNo, params.get("refundBizNo"));
		wrapper.lambda().in(ObjectUtil.isNotEmpty(params.get("refundStatus")), OrderRefund::getRefundStatus, Func.toLongList(String.valueOf(params.get("refundStatus"))));
		wrapper.lambda().eq(ObjectUtil.isNotEmpty(params.get("refundMoneyStatus")), OrderRefund::getRefundMoneyStatus, params.get("refundMoneyStatus"));
		wrapper.lambda().eq(ObjectUtil.isNotEmpty(params.get("logisticsNo")), OrderRefund::getLogisticsNo, params.get("logisticsNo"));
		wrapper.lambda().ge(ObjectUtil.isNotEmpty(params.get("createTimeBegin")), OrderRefund::getCreateTime, params.get("createTimeBegin"));
		wrapper.lambda().le(ObjectUtil.isNotEmpty(params.get("createTimeEnd")), OrderRefund::getCreateTime, params.get("createTimeEnd"));
		wrapper.lambda().orderByDesc(OrderRefund::getId);
		return wrapper;
	}

	/**
	 * excel导出
	 */
	public List<OrderRefundExcel> selectOrderRefundExcel(Map<String, Object> params) {
		return BeanUtil.copy(baseMapper.selectOrderRefundPage(null, params), OrderRefundExcel.class);
	}

	/**
	 * 售后单号查找
	 */
	public OrderRefund getByRefundNo(String refundBizNo) {
		return baseMapper.selectOne(Wrappers.<OrderRefund>lambdaQuery().eq(OrderRefund::getRefundNo, refundBizNo));
	}

	/**
	 * 订单金额统计
	 */
	public Double sumByParams(Map<String, Object> params) {
		return sumByParams(params, "goods_price");
	}

	/**
	 * 订单金额统计
	 */
	public Double sumByParams(Map<String, Object> params, String field) {
		QueryWrapper<OrderRefund> wrapper = selectOrderRefundWrapper(params);
		wrapper.select(StringUtil.format("ifnull(sum({}),0) as total", field));
		return Double.valueOf(getMap(wrapper).get("total").toString());
	}

	/**
	 * 订单数量统计
	 */
	public long countByParams(Map<String, Object> params) {
		return count(selectOrderRefundWrapper(params));
	}


	/**
	 * 买家售后申请
	 */
	@Transactional(rollbackFor = Exception.class)
    public Long buyerApply(OrderRefundDTO.ApplyDTO applyDTO, boolean isVerifyExpireTime) {
		Date now = new Date();
		Order order = orderService.getById(applyDTO.getOrderId());
		Assert.isNull(order, "订单号不存在");
		Assert.isTrue(order.getOrderStatus() >= 1, "当前订单不可申请售后");

		OrderDetail orderDetail = orderDetailService.getById(applyDTO.getOrderDetailId());
		Assert.isNull(orderDetail, "订单详情不存在");
		Assert.isTrue(orderDetail.getOrderNo().equals(order.getOrderNo()), MsgConstant.UNAUTHORIZED);
		Assert.isTrue(orderDetail.getRefundStatus() == 0, "当前商品售后正在审核中");
		if(applyDTO.getGoodsNum() > (orderDetail.getGoodsNum() - orderDetail.getRefundNum())){
			throw new ServiceException("申请数量超出商品可申请数");
		}

		if(isVerifyExpireTime && order.getOrderStatus().equals(OrderStatusEnum.SUCCESS.getStatus())){
			//维权期
			ConfigDTO.ShopDTO config = ConfigCache.getObject(ConfigKeys.SHOP, ConfigDTO.ShopDTO.class);
			Date expireTime = DateUtil.offsetDay(order.getFinishTime(), config.getRefund());
			if(DateUtil.compare(now, expireTime) > 0){
				throw new ServiceException("订单已超过维权期");
			}
		}

		OrderSettle orderSettle = orderSettleService.getByOrderNo(order.getOrderNo());
		Assert.isNull(orderSettle, "结算单号不存在");

		OrderRefund orderRefund = new OrderRefund();
		orderRefund.setSellerId(order.getSellerId());
		orderRefund.setUserId(order.getUserId());
		orderRefund.setPayType(orderSettle.getPayType());
		orderRefund.setPayNo(orderSettle.getPayNo());
		orderRefund.setPayBizNo(orderSettle.getPayBizNo());
		orderRefund.setOrderId(order.getId());
		orderRefund.setOrderNo(order.getOrderNo());
		orderRefund.setOrderType(order.getOrderType());
		orderRefund.setOrderDetailId(orderDetail.getId());
		orderRefund.setGoodsId(orderDetail.getGoodsId());
		orderRefund.setGoodsNum(applyDTO.getGoodsNum());
		orderRefund.setGoodsPrice(orderDetail.getGoodsPrice());
		orderRefund.setGoodsPriceTotal(Arith.mul(applyDTO.getGoodsNum(), orderDetail.getGoodsPrice()));
		orderRefund.setGoodsStatus(applyDTO.getGoodsStatus());
		orderRefund.setGoodsDetail(orderDetail.getGoodsDetail());
		orderRefund.setRefundNo(snowflakeUtil.snowflakeId());
		orderRefund.setRefundType(applyDTO.getRefundType());
		orderRefund.setRefundStatus(0);
		orderRefund.setRefundStatusPath("0");
		orderRefund.setRefundMoneyStatus(0);
		orderRefund.setRefundMoney(calculateRefund(orderDetail.getOrderPrice(), orderDetail.getGoodsNum(), applyDTO.getGoodsNum(), orderDetail.getRefundNum()));
		orderRefund.setReturnDeductMoney(calculateRefund(orderDetail.getDeductMoney(), orderDetail.getGoodsNum(), applyDTO.getGoodsNum(), orderDetail.getRefundNum()));
		orderRefund.setReturnDeductIntegral(calculateRefund(orderDetail.getDeductIntegral(), orderDetail.getGoodsNum(), applyDTO.getGoodsNum(), orderDetail.getRefundNum()));
		orderRefund.setBuyerImg(applyDTO.getBuyerImg());
		orderRefund.setBuyerMsg(applyDTO.getBuyerMsg());
		orderRefund.setSellerMsg("");
		orderRefund.setCreateTime(now);
		save(orderRefund);

		//保存记录
		OrderRefundLog orderRefundLog = new OrderRefundLog();
		orderRefundLog.setRefundId(orderRefund.getId());
		orderRefundLog.setRemark("售后申请已提交，等待商家审核");
		orderRefundLog.setCreateTime(now);
		orderRefundLogService.save(orderRefundLog);

		//更新订单明细售后状态
		orderDetailService.updateById(OrderDetail.builder().id(orderDetail.getId()).refundStatus(1).build());
		orderDetailService.removeCacheByOrderNo(orderRefund.getOrderNo());

		//更新订单状态
		orderService.updateById(Order.builder().id(order.getId()).refundStatus(1).updateTime(now).build());
		return orderRefund.getId();
    }

	/**
	 * 计算退款金额
	 *
	 * @param totalMoney 总支付金额
	 * @param totalGoodsNum 总商品数量
	 * @param returnGoodsNum 即将退款的商品数量
	 * @param totalReturnGoodsNum 已退款的商品数量
	 * @return 本次退款的金额
	 */
	public static double calculateRefund(double totalMoney, int totalGoodsNum, int returnGoodsNum, int totalReturnGoodsNum) {
		if (totalMoney <= 0 || totalGoodsNum <= 0) {
			return 0d;
		}

		//可退商品数
		int canReturnGoodsNum = totalGoodsNum - totalReturnGoodsNum;
		if (canReturnGoodsNum <= 0) {
			return 0d;
		}

		//单个商品退款金额
		double unitReturnMoney = Arith.div(totalMoney, totalGoodsNum);
		//已退款金额
		double totalReturnMoney = Arith.mul(unitReturnMoney, totalReturnGoodsNum);
		//可退款金额
		double residueReturnMoney = Arith.sub(totalMoney, totalReturnMoney);
		if(residueReturnMoney <= 0){
			return 0d;
		}

		// 判断是否为最后一批退款
		boolean isLastBatch = (totalReturnGoodsNum + returnGoodsNum) >= totalGoodsNum;
		double refundMoney;
		if (isLastBatch) {
			refundMoney = residueReturnMoney;
		} else {
			refundMoney = Math.min(Arith.mul(unitReturnMoney, returnGoodsNum), residueReturnMoney);
		}
		return refundMoney;
	}

//	public static void main(String[] args) {
//		// 示例参数
//		double totalMoney = 0;
//		int totalGoodsNum = 5;
//		int totalReturnGoodsNum = 0; // 已退款的商品数量
//		int[] itemsToRefundArray = {5}; // 模拟退款次数
//
//		double totalRefunded = 0d;
//		for (int itemsToRefund  : itemsToRefundArray) {
//			double refundAmount = calculateRefund(totalMoney, totalGoodsNum, itemsToRefund, totalReturnGoodsNum);
//			System.out.println("Refund Amount: " + refundAmount + " 退款数量：" + itemsToRefund + " 已退款数量：" + totalReturnGoodsNum);
//			totalRefunded = Arith.add(totalRefunded, refundAmount);
//			totalReturnGoodsNum += itemsToRefund;
//		}
//
//		// 验证退款总额与支付总额是否匹配
//		System.out.println("Total Refunded: " + totalRefunded);
//		System.out.println("Original Payment: " + totalMoney);
//	}

	/**
	 * 买家取消售后
	 */
	@Transactional(rollbackFor = Exception.class)
	public boolean buyerCancel(String id) {
		Date now = new Date();
		OrderRefund orderRefund = getById(id);
		Assert.isNull(orderRefund, MsgConstant.OBJECT_NULL);
		Assert.isTrue(orderRefund.getRefundStatus() == 0, "当前售后订单状态不取消");

		//更新售后订单状态
		updateById(OrderRefund.builder()
			.id(orderRefund.getId())
			.refundStatus(-2)
			.refundStatusPath(orderRefund.getRefundStatusPath().concat(",-2"))
			.build());
		//更新订单明细售后状态
		orderDetailService.updateById(OrderDetail.builder().id(orderRefund.getOrderDetailId()).refundStatus(0).build());
		orderDetailService.removeCacheByOrderNo(orderRefund.getOrderNo());
		//更新订单状态
		if(!orderDetailService.isExistRefundStatus1(orderRefund.getOrderNo())){
			orderService.updateById(Order.builder().id(orderRefund.getOrderId()).refundStatus(0).updateTime(now).build());
		}

		OrderRefundLog orderRefundLog = new OrderRefundLog();
		orderRefundLog.setRefundId(orderRefund.getId());
		orderRefundLog.setRemark("买家取消售后");
		orderRefundLog.setCreateTime(now);
		orderRefundLogService.save(orderRefundLog);
		orderRefundLogService.removeCacheByRefundId(orderRefund.getId());
		return true;
	}

	/**
	 * 卖家拒绝退货
	 */
	@Transactional(rollbackFor = Exception.class)
	public boolean sellerReject(OrderRefundDTO.RejectDTO rejectDTO) {
		Date now = new Date();
		OrderRefund orderRefund = getById(rejectDTO.getId());
		Assert.isNull(orderRefund, MsgConstant.OBJECT_NULL);
		Assert.isTrue(orderRefund.getRefundStatus() == 0 || orderRefund.getRefundStatus() == 2, "当前售后订单状态不拒绝");

		//更新售后订单状态
		updateById(OrderRefund.builder()
			.id(orderRefund.getId())
			.refundStatus(-1)
			.refundStatusPath(orderRefund.getRefundStatusPath().concat(",-1"))
			.handelTime(now)
			.sellerMsg(rejectDTO.getSellerMsg())
			.build());
		//更新订单明细售后状态
		orderDetailService.updateById(OrderDetail.builder().id(orderRefund.getOrderDetailId()).refundStatus(0).build());
		orderDetailService.removeCacheByOrderNo(orderRefund.getOrderNo());
		//更新订单状态
		if(!orderDetailService.isExistRefundStatus1(orderRefund.getOrderNo())){
			orderService.updateById(Order.builder().id(orderRefund.getOrderId()).refundStatus(0).updateTime(now).build());
		}

		OrderRefundLog orderRefundLog = new OrderRefundLog();
		orderRefundLog.setRefundId(orderRefund.getId());
		orderRefundLog.setRemark("商家拒绝售后申请");
		orderRefundLog.setCreateTime(now);
		orderRefundLogService.save(orderRefundLog);
		orderRefundLogService.removeCacheByRefundId(orderRefund.getId());

		//推送消息
		NoticeDTO noticeDTO = new NoticeDTO();
		noticeDTO.setTargetId(orderRefund.getId());
		noticeDTO.setType(NoticeTypeEnum.ORDER_REFUND.getType());
		redisDelayQueueUtil.addDelayQueue(noticeDTO, 1, RedisDelayQueueEnum.NOTICE.getCode());
		return true;
	}

	/**
	 * 卖家同意申请
	 */
	@Transactional(rollbackFor = Exception.class)
	public boolean sellerAgreeApply(OrderRefundDTO.ApplyAgreeDTO applyAgreeDTO) {
		Date now = new Date();
		OrderRefund orderRefund = getById(applyAgreeDTO.getId());
		Assert.isNull(orderRefund, MsgConstant.OBJECT_NULL);
		Assert.isTrue(orderRefund.getRefundType() == 2 && orderRefund.getRefundStatus() == 0, "当前售后订单状态不可同意");

		SellerAddress sellerAddress = sellerAddressService.getById(applyAgreeDTO.getSellerAddressId());
		Assert.isNull(sellerAddress, "请选择退货地址");

		//更新售后订单状态
		updateById(OrderRefund.builder()
			.id(orderRefund.getId())
			.refundStatus(1)
			.refundStatusPath(orderRefund.getRefundStatusPath().concat(",1"))
			.refundAddress(JsonUtil.toJson(sellerAddress))
			.handelTime(now)
			.build());

		OrderRefundLog orderRefundLog = new OrderRefundLog();
		orderRefundLog.setRefundId(orderRefund.getId());
		orderRefundLog.setRemark("商家已同意，请点击下方按钮，完善退货信息");
		orderRefundLog.setCreateTime(now);
		orderRefundLogService.save(orderRefundLog);
		orderRefundLogService.removeCacheByRefundId(orderRefund.getId());

		//推送消息
		NoticeDTO noticeDTO = new NoticeDTO();
		noticeDTO.setTargetId(orderRefund.getId());
		noticeDTO.setType(NoticeTypeEnum.ORDER_REFUND.getType());
		redisDelayQueueUtil.addDelayQueue(noticeDTO, 1, RedisDelayQueueEnum.NOTICE.getCode());
		return true;
	}

	/**
	 * 买家寄回货物
	 */
	@Transactional(rollbackFor = Exception.class)
	public boolean buyerLogisticsSave(OrderRefundDTO.LogisticsDTO logisticsDTO) {
		Date now = new Date();
		OrderRefund orderRefund = getById(logisticsDTO.getId());
		Assert.isNull(orderRefund, MsgConstant.OBJECT_NULL);
		Assert.isTrue(orderRefund.getRefundStatus() == 1, "当前售后订单状态不可退货");

		//更新售后订单状态
		updateById(OrderRefund.builder()
			.id(orderRefund.getId())
			.refundStatus(2)
			.refundStatusPath(orderRefund.getRefundStatusPath().concat(",2"))
			.logisticsType(logisticsDTO.getLogisticsType())
			.logisticsNo(logisticsDTO.getLogisticsNo())
			.logisticsName(logisticsDTO.getLogisticsName())
			.build());

		OrderRefundLog orderRefundLog = new OrderRefundLog();
		orderRefundLog.setRefundId(orderRefund.getId());
		orderRefundLog.setRemark("买家已退货，等待商家确认收货");
		orderRefundLog.setCreateTime(now);
		orderRefundLogService.save(orderRefundLog);
		orderRefundLogService.removeCacheByRefundId(orderRefund.getId());
		return true;
	}

	/**
	 * 买家修改物流
	 */
	@Transactional(rollbackFor = Exception.class)
	public boolean buyerLogisticsUpdate(OrderRefundDTO.LogisticsDTO logisticsDTO) {
		OrderRefund orderRefund = getById(logisticsDTO.getId());
		Assert.isNull(orderRefund, MsgConstant.OBJECT_NULL);
		Assert.isTrue(orderRefund.getRefundStatus() == 2, "当前售后订单状态不可修改");

		//更新售后订单状态
		updateById(OrderRefund.builder()
			.id(orderRefund.getId())
			.logisticsType(logisticsDTO.getLogisticsType())
			.logisticsNo(logisticsDTO.getLogisticsNo())
			.logisticsName(logisticsDTO.getLogisticsName())
			.build());
		return true;
	}

	/**
	 * 卖家确认收货
	 */
	@Transactional(rollbackFor = Exception.class)
	public boolean sellerAgreeShipping(Serializable id) {
		Date now = new Date();
		OrderRefund orderRefund = getById(id);
		Assert.isNull(orderRefund, MsgConstant.OBJECT_NULL);
		Assert.isTrue((orderRefund.getRefundType() == 1 && orderRefund.getRefundStatus() == 0) || (orderRefund.getRefundType() == 2 && orderRefund.getRefundStatus() == 2), "当前售后订单状态不可确认");

		//更新售后订单状态
		updateById(OrderRefund.builder()
			.id(orderRefund.getId())
			.refundStatus(3)
			.refundMoneyStatus(orderRefund.getRefundMoney() > 0 ? 1 : 2)
			.refundStatusPath(orderRefund.getRefundStatusPath().concat(",3"))
			.handelTime(ObjectUtil.isEmpty(orderRefund.getHandelTime()) ? now : null)
			.refundTime(now)
			.build());

		//更新订单明细售后状态
		OrderDetail orderDetail = orderDetailService.getById(orderRefund.getOrderDetailId());
		orderDetailService.updateById(OrderDetail.builder().id(orderDetail.getId()).refundStatus(0).refundNum(orderDetail.getRefundNum() + orderRefund.getGoodsNum()).build());
		orderDetailService.removeCacheByOrderNo(orderRefund.getOrderNo());
		//更新订单状态
		if(!orderDetailService.isExistRefundStatus1(orderRefund.getOrderNo())){
			//判断状态要变成无售后还是已完成
			List<OrderDetail> orderDetailList = orderDetailService.listByOrderNo(orderRefund.getOrderNo());
			int goodsNum = orderDetailList.stream().mapToInt(OrderDetail::getGoodsNum).sum();
			int refundNum = orderDetailList.stream().mapToInt(OrderDetail::getRefundNum).sum();
			if(refundNum >= goodsNum){
				orderService.updateById(Order.builder().id(orderRefund.getOrderId()).orderStatus(3).refundStatus(2).updateTime(now).build());
			}else{
				orderService.updateById(Order.builder().id(orderRefund.getOrderId()).refundStatus(0).updateTime(now).build());
			}
		}

		//更新结算单的结算信息
		if(orderRefund.getRefundMoney() > 0){
			OrderSettle orderSettle = orderSettleService.getByOrderNo(orderRefund.getOrderNo());
			//服务费 =（支付金额 - 总退款金额）* 手续费比例
			double refundMoney = Arith.add(orderSettle.getRefundAmount(), orderRefund.getRefundMoney());
			double payAmount = Arith.sub(orderSettle.getPayAmount(), refundMoney);
			double serveAmount = Arith.round(Arith.mul(payAmount, Arith.div(orderSettle.getServeRatio(), 100, 4))).doubleValue();

			//佣金处理
			double directMoney = 0d;
			if(orderDetail.getDirectMoney() > 0){
				directMoney = calculateRefund(orderDetail.getDirectMoney(), orderDetail.getGoodsNum(), orderRefund.getGoodsNum(), orderDetail.getRefundNum());
				OrderSettlePlace orderSettlePlace = orderSettlePlaceService.getOne(Wrappers.<OrderSettlePlace>lambdaQuery()
					.eq(OrderSettlePlace::getPayNo, orderRefund.getPayNo()).eq(OrderSettlePlace::getSettleType, WalletSourceEnum.DIRECT.getType())
				);
				if(ObjectUtil.isNotEmpty(orderSettlePlace)){
					double settleAmount = Arith.sub(orderSettlePlace.getSettleAmount(), directMoney);
					orderSettlePlaceService.updateById(OrderSettlePlace.builder()
						.id(orderSettlePlace.getId())
						.refundAmount(refundMoney)
						.settleAmount(settleAmount)
						.build()
					);
				}
			}
			double indirectMoney = 0d;
			if(orderDetail.getIndirectMoney() > 0){
				indirectMoney = calculateRefund(orderDetail.getIndirectMoney(), orderDetail.getGoodsNum(), orderRefund.getGoodsNum(), orderDetail.getRefundNum());
				OrderSettlePlace orderSettlePlace = orderSettlePlaceService.getOne(Wrappers.<OrderSettlePlace>lambdaQuery()
					.eq(OrderSettlePlace::getPayNo, orderRefund.getPayNo()).eq(OrderSettlePlace::getSettleType, WalletSourceEnum.INDIRECT.getType())
				);
				if(ObjectUtil.isNotEmpty(orderSettlePlace)){
					double settleAmount = Arith.sub(orderSettlePlace.getSettleAmount(), indirectMoney);
					orderSettlePlaceService.updateById(OrderSettlePlace.builder()
						.id(orderSettlePlace.getId())
						.refundAmount(refundMoney)
						.settleAmount(settleAmount)
						.build()
					);
				}
			}

			//商户结算金额
			double settleAmount = Arith.sub(payAmount, serveAmount, directMoney, indirectMoney).doubleValue();
			orderSettleService.updateById(OrderSettle.builder()
				.id(orderSettle.getId())
				.serveAmount(serveAmount)
				.settleAmount(settleAmount)
				.refundAmount(refundMoney)
				.build()
			);
		}

		//记录售后单日志
		OrderRefundLog orderRefundLog = new OrderRefundLog();
		orderRefundLog.setRefundId(orderRefund.getId());
		orderRefundLog.setRemark("商家已同意，退款处理中");
		orderRefundLog.setCreateTime(now);
		orderRefundLogService.save(orderRefundLog);
		orderRefundLogService.removeCacheByRefundId(orderRefund.getId());

		//退优惠券
		orderCouponService.listByOrderNo(orderRefund.getOrderNo()).forEach(orderCoupon -> {
			CouponUser couponUser = JsonUtil.parse(orderCoupon.getCouponInfo(), CouponUser.class);
			if(!DateUtil.isIn(now, couponUser.getBeginTime(), couponUser.getEndTime())){
				return;
			}
			if(CouponUseTypeEnum.COMMON.getType() == orderCoupon.getCouponUseType()){
				List<String> orderNo = Func.toStrList(orderCoupon.getOrderNo());
				long count = orderService.count(Wrappers.<Order>lambdaQuery().in(Order::getOrderNo, orderNo).eq(Order::getRefundStatus, 2));
				if(orderNo.size() == count){
					couponUserService.updateById(CouponUser.builder().id(couponUser.getId()).status(0).build());
				}
			}else if(CouponUseTypeEnum.GOODS.getType() == orderCoupon.getCouponUseType()){
				String orderNo = orderCoupon.getOrderNo();
				List<Long> goodsIds = Func.toLongList(orderCoupon.getTargetKey());
				List<OrderDetail> orderDetailList = orderDetailService.list(Wrappers.<OrderDetail>lambdaQuery().eq(OrderDetail::getOrderNo, orderNo).in(OrderDetail::getGoodsId, goodsIds));
				int goodsNum = orderDetailList.stream().mapToInt(OrderDetail::getGoodsNum).sum();
				int refundNum = orderDetailList.stream().mapToInt(OrderDetail::getRefundNum).sum();
				if(refundNum >= goodsNum){
					couponUserService.updateById(CouponUser.builder().id(couponUser.getId()).status(0).build());
				}
			}else if(CouponUseTypeEnum.SELLER.getType() == orderCoupon.getCouponUseType()){
				String orderNo = orderCoupon.getOrderNo();
				long count = orderService.count(Wrappers.<Order>lambdaQuery().eq(Order::getOrderNo, orderNo).eq(Order::getRefundStatus, 2));
				if(count >= 1){
					couponUserService.updateById(CouponUser.builder().id(couponUser.getId()).status(0).build());
				}
			}
		});
		//退余额
		if(orderRefund.getReturnDeductMoney() > 0){
			userService.updateUserMoney(WalletDTO.builder()
				.userId(orderRefund.getUserId())
				.amount(orderRefund.getReturnDeductMoney())
				.type(WalletTypeEnum.ADD.getType())
				.sourceId(orderRefund.getRefundNo())
				.sourceType(WalletSourceEnum.ORDER_REFUND.getType())
				.remark(StringUtil.format("售后单号-{}", orderRefund.getRefundNo()))
				.build());
		}
		//退积分
		if(orderRefund.getReturnDeductIntegral() > 0){
			userService.updateUserIntegral(WalletDTO.builder()
				.userId(orderRefund.getUserId())
				.amount(orderRefund.getReturnDeductIntegral())
				.type(WalletTypeEnum.ADD.getType())
				.sourceId(orderRefund.getRefundNo())
				.sourceType(WalletSourceEnum.ORDER_REFUND.getType())
				.remark(StringUtil.format("售后单号-{}", orderRefund.getRefundNo()))
				.build());
		}
		//退现金
		if(orderRefund.getRefundMoney() > 0){
			Order order = orderService.getByOrderNo(orderRefund.getOrderNo());
			RefundDTO refundDTO = new RefundDTO();
			refundDTO.setPayNo(orderRefund.getPayNo());
			refundDTO.setPayBizNo(orderRefund.getPayBizNo());
			refundDTO.setRefundNo(orderRefund.getRefundNo());
			refundDTO.setRefundMoney(orderRefund.getRefundMoney());
			refundDTO.setTotalMoney(order.getOrderPrice());
			refundDTO.setNotifyUrl("/api/server-pay/notify/order/refund");
			OrderGoodsVO orderGoodsVO = JsonUtil.parse(orderRefund.getGoodsDetail(), OrderGoodsVO.class);
			Kv params = Kv.create().set("goodsId", orderRefund.getGoodsId()).set("goodsName", orderGoodsVO.getName())
				.set("goodsUnitPrice", orderRefund.getGoodsPrice()).set("goodsNum", orderRefund.getGoodsNum());
			refundDTO.setParams(params);
			IPayGranter payGranter = PayGranterBuilder.getGranter(orderRefund.getPayType());
			RefundVO refundVO = payGranter.refund(refundDTO);
			if(refundVO.getCode().equals(StringPool.NO)){
				throw new ServiceException(refundVO.getMsg());
			}
		}else{
			OrderRefundLog refundLog = new OrderRefundLog();
			refundLog.setRefundId(orderRefund.getId());
			refundLog.setRemark("退款成功，请注意查收你的账户");
			refundLog.setCreateTime(now);
			orderRefundLogService.save(refundLog);
			orderRefundLogService.removeCacheByRefundId(orderRefund.getId());
		}

		//推送消息
		NoticeDTO noticeDTO = new NoticeDTO();
		noticeDTO.setTargetId(orderRefund.getId());
		noticeDTO.setType(NoticeTypeEnum.ORDER_REFUND.getType());
		redisDelayQueueUtil.addDelayQueue(noticeDTO, 1, RedisDelayQueueEnum.NOTICE.getCode());
		return true;
	}

	/**
	 * 卖家重新打款
	 */
	@Transactional(rollbackFor = Exception.class)
	public boolean sellerAgainPay(Serializable id) {
		OrderRefund orderRefund = getById(id);
		Assert.isNull(orderRefund, MsgConstant.OBJECT_NULL);
		Assert.isTrue(orderRefund.getRefundStatus() == 3, "当前售后订单状态不可重新打款");
		Assert.isTrue(orderRefund.getRefundMoneyStatus() == -1, "当前售后订单状态不可重新打款");
		Assert.isTrue(orderRefund.getRefundMoney() > 0, "当前售后订单无实际支付金额");
		//取支付单号
		Order order = orderService.getByOrderNo(orderRefund.getOrderNo());
		RefundDTO refundDTO = new RefundDTO();
		refundDTO.setPayNo(orderRefund.getPayNo());
		refundDTO.setPayBizNo(orderRefund.getPayBizNo());
		refundDTO.setRefundNo(orderRefund.getRefundNo());
		refundDTO.setRefundMoney(orderRefund.getRefundMoney());
		refundDTO.setTotalMoney(order.getOrderPrice());
		refundDTO.setNotifyUrl("/order/refund");
		refundDTO.setParams(Kv.create().set("userId", order.getUserId()));
		IPayGranter payGranter = PayGranterBuilder.getGranter(orderRefund.getPayType());
		RefundVO refundVO = payGranter.refund(refundDTO);
		if(refundVO.getCode().equals(StringPool.NO)){
			throw new ServiceException(refundVO.getMsg());
		}

		//更新售后订单状态
		updateById(OrderRefund.builder().id(orderRefund.getId()).refundMoneyStatus(1).build());
		return true;
	}

	/**
	 * 订单退款通知
	 */
	@Transactional(rollbackFor = Exception.class)
	public boolean refundNotify(String refundNo, String refundBizNo, boolean status) {
		Date now = new Date();
		OrderRefund orderRefund = getByRefundNo(refundNo);
		Assert.isNull(orderRefund, MsgConstant.OBJECT_NULL);
		Assert.isTrue(orderRefund.getRefundStatus() == 3, "当前售后订单状态不可修改");
		Assert.isTrue(orderRefund.getRefundMoneyStatus() == 1, "当前售后订单退款状态不可修改");

		//退款成功
		if(status){
			//更新售后订单状态
			updateById(OrderRefund.builder().id(orderRefund.getId()).refundBizNo(refundBizNo).refundMoneyStatus(2).build());
			OrderRefundLog orderRefundLog = new OrderRefundLog();
			orderRefundLog.setRefundId(orderRefund.getId());
			orderRefundLog.setRemark("退款成功，请注意查收你的账户");
			orderRefundLog.setCreateTime(now);
			orderRefundLogService.save(orderRefundLog);
			orderRefundLogService.removeCacheByRefundId(orderRefund.getId());
		}else{
			//更新售后订单状态
			updateById(OrderRefund.builder().id(orderRefund.getId()).refundBizNo(refundBizNo).refundMoneyStatus(-1).build());
		}
		return true;
	}

}

